#include <memory/memorymanagement.h>


    MemoryManager* first;

    MemoryManager* MemoryManager::activeMemoryManager = 0;

    MemoryManager::MemoryManager(size_t start, size_t size){

        activeMemoryManager = this;


        if(size < sizeof(MemoryChunk)){
            first = 0;
        }
        else{

        first = (MemoryChunk*) start;
        
        first->allocated = false;
        first->pre = 0;
        first->next = 0;
        first->size = size - sizeof(MemoryChunk);

        }

    }
    MemoryManager::~MemoryManager(){

        if(activeMemoryManager == this){
            activeMemoryManager = 0;
        }

    }

    void* MemoryManager::malloc(size_t size){

        MemoryChunk *result = 0;
        for(MemoryChunk* chunk = first; chunk != 0; chunk = chunk->next){
            if(chunk->size > size && !chunk->allocated)
                result = chunk;
        }

        if(result == 0)
            return 0;

        if(result->size < size + sizeof(MemoryChunk) + 1){

            result->allocated = true;

        }
        else
        {
            MemoryChunk* temp = (MemoryChunk*)((size_t)result + sizeof(MemoryChunk) + size);

            temp->allocated = false;
            temp->size = result->size - size - sizeof(MemoryChunk);
            temp->pre = result;
            temp->next = result->next;
            if(temp->next != 0 )
                temp->next->pre = temp;
            
            result->size = size;
            result->next = temp;

        }

        result->allocated = true;

        return (void*)(((size_t)result) + sizeof(MemoryChunk));

    }
    
    void MemoryManager::free(void* ptr){


        MemoryChunk* chunk = (MemoryChunk*) ((size_t)ptr - sizeof(MemoryChunk));

        chunk->allocated = false;

        if(chunk->pre != 0 && !chunk->pre->allocated){
            chunk->pre->next = chunk->next;
            chunk->pre->size += chunk->size + sizeof(MemoryChunk);
            if(chunk->next != 0)
                chunk->next->pre = chunk->next;

            chunk = chunk->pre;

        }

        if(chunk->next != 0 && !chunk->next->allocated){
            chunk->next = chunk->next->next;
            chunk->size += chunk->next->size + sizeof(MemoryChunk);
            if(chunk->next != 0)
                chunk->next->pre = chunk;

            
        }

    }





void* operator new(unsigned int size) {
    if(MemoryManager::activeMemoryManager == 0) {
        return 0;
    }
    return MemoryManager::activeMemoryManager->malloc(size);
}

void* operator new[](unsigned int size) {
    if(MemoryManager::activeMemoryManager == 0) {
        return 0;
    }
    return MemoryManager::activeMemoryManager->malloc(size);
}

void* operator new(unsigned int size, void* ptr) {
    return ptr;
}

void* operator new[](unsigned int size, void* ptr) {
    return ptr;
}

void operator delete(void* ptr) {
    if(MemoryManager::activeMemoryManager == 0) {
        return;
    }
    return MemoryManager::activeMemoryManager->free(ptr);
}

void operator delete[](void* ptr) {
    if(MemoryManager::activeMemoryManager == 0) {
        return;
    }
    return MemoryManager::activeMemoryManager->free(ptr);
}